#pragma once //避免头文件重复包含
#include<pthread.h>
#include<unordered_map>
#include<unistd.h>
#include<string>
#include<vector>
#include"util.hpp"
#include"config.hpp"

namespace cloud
{
    typedef struct BackupInfo
    {
        bool pack_flag;
        size_t fsize;
        time_t atime;
        time_t mtime;
        std::string real_path;
        std::string pack_path;
        std::string url;
        bool NewBackupInfo(const std::string& realpath)
        {
            Cloud::FileUtil fu(realpath);
            if(fu.Exists() == false)
            {
                std::cout << "文件不存在" << std::endl;
                return false;
            }
            Config* config = Config::GetInstance();
            std::string packdir = config->GetPackDir();
            std::string packsuffix= config->GetPackFileSuffix();
            std::string download_prefix = config->GetDownloadPrefix();
            
            this->pack_flag = false;
            this->fsize = fu.FileSize();
            this->mtime = fu.LastModTime();
            this->atime = fu.LastAccTime();
            this->real_path = realpath;
            this->pack_path = packdir + fu.FileName() + packsuffix;//pack_path是压缩包的存储路径 假设原本文件实际存储路径是./backdir/a.txt被压缩后就要放到./packdir/a.txt.lz 路径发生改变且多了一个后缀名所以要获取两个东西
                             //一个是路径一个是后缀名所以要先拿去到配置文件中的后缀名和路径
            this->url = download_prefix + fu.FileName();
            return true;
        }
    }BackupInfo;

    
    class DataManager
    {
    public:
        //构造函数
        DataManager()
        {
            _backup_file = Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&_rwlock,nullptr); //初始化读写锁
            InitLoad(); //初始化加载要在每次系统重启时候加载以前的数据

        }

        //析构函数
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock); //销毁读写锁

        }

        //新增
        bool Insert(const BackupInfo& info)
        {
            pthread_rwlock_wrlock(&_rwlock); //上锁
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            this->Storage(); //新增或者更改就要加入持久化存储数据的文件当中
            return true;
        }

        //更新
        bool Update(const BackupInfo& info)
        {
            pthread_rwlock_wrlock(&_rwlock); //上锁
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            this->Storage(); 
            return true;
        }

        //通过url在哈希表中查找对应的数据
        bool GetOneByURL(const std::string& url,BackupInfo* info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            //因为url在哈希表中是key值，所以直接find进行查找
            auto it = _table.find(url);
            if(it == _table.end())
            {
                pthread_rwlock_unlock(&_rwlock);
                return false; //没找到
            }
            *info = it->second;
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
    
    bool GetOneByRealPath(const std::string& realpath,BackupInfo* info)
    {
        pthread_rwlock_wrlock(&_rwlock);
        auto it = _table.begin();
        for(; it != _table.end(); ++it)
        {
            if(it->second.real_path == realpath)
            {
                *info = it->second;
                pthread_rwlock_unlock(&_rwlock);
                return true;
            }
        }
        pthread_rwlock_unlock(&_rwlock);
        return false;
    }

    //获取哈希表中存储的所有数据
    bool GetAll(std::vector<BackupInfo>* arry)
    {
        pthread_rwlock_wrlock(&_rwlock);
        auto it = _table.begin();
        for(; it != _table.end(); ++it)
        {
            arry->push_back(it->second);
        }
        pthread_rwlock_unlock(&_rwlock);
        return true;
    }

    //把所有的数据获取出来组织成一个json格式的数据再存储起来
    bool Storage()
    {
        //1.获取所有数据
        std::vector<BackupInfo> arry;
        this->GetAll(&arry);
        
        //2.添加到json::value中
        Json::Value root;
        for(int i=0; i<arry.size(); i++)
        {
            Json::Value item;
            root["pack_flag"] = arry[i].pack_flag;
            root["fsize"] = (Json::Int64)arry[i].fsize; //json库通常会定义特定类型来表示json中的整数值,和C++中表示整形的类型不同所以要强转
            root["atime"] = (Json::Int64)arry[i].atime;
            root["mtime"] = (Json::Int64)arry[i].mtime;
            root["real_path"] = arry[i].real_path;
            root["pack_path"] = arry[i].pack_path;
            root["url"] = arry[i].url;
            root.append(item); //添加数组元素
        }
        
        //3.对josn::value序列化
        std::string body;
        Cloud::JsonUtil::Serialize(root,&body);
        //4.写入文件
        Cloud::FileUtil fu(_backup_file);
        fu.SetContent(body);
        
        return true;
    }

    //初始化:加载
    bool InitLoad()
    {
        //1.将数据文件中的数据读取出来
        Cloud::FileUtil fu(_backup_file);
        //如果文件不存在就返回false
        if(fu.Exists() == false)
        {
            return false;
        }
        std::string body;
        fu.GetContent(&body);
        
        //2.反序列化
        Json::Value root;
        Cloud::JsonUtil::UnSerialize(body,&root);
        
        //3.将反序列化得到的json::value中的数据添加到table中
        for(int i=0; i<root.size(); i++)
        {
            BackupInfo info;
            info.pack_flag = root[i]["pack_flag"].asBool();
            info.fsize = root[i]["pack_flag"].asInt64();
            info.atime = root[i]["atime"].asInt64();
            info.mtime = root[i]["mtime"].asInt64();
            info.pack_path = root[i]["pack_path"].asString();
            info.real_path = root[i]["real_path"].asString();
            info.url = root[i]["url"].asString();
        }   
    return true;
    }    


    private:
        std::string _backup_file; //数据持久化存储文件
        pthread_rwlock_t _rwlock; //读写锁
        std::unordered_map<std::string,BackupInfo> _table;
    };
};
